import asyncio
import functools
from typing import List, Union

from pywebio import output, pin
from emi.bar.data import CategorySymbolMeta, CategoryMeta
from emi.bar.storage import MarketMetaStorage
from emi.core.App import App
from emi.core.task import Task
from emi.model import Market, PageResult, default_page_result
from emiui import dialog, UISession
from emiui.ui._RankDBUI import RankDBUI


class MarketUI:

    def __init__(self, market: Market,app:App,download_market_meta_task:Task = None):
        self.market = market
        self.app = app
        self.download_market_meta_task = download_market_meta_task
        self.symbol_manager = None

    async def show(self):
        """
        成分股
        [code,name,category_name]
        """
        market = self.market
        market_meta = market.get_meta()

        if self.download_market_meta_task:
            ui_session = UISession.get(self.app.getTaskManager())
            output.put_row([
                #output.put_button("更新行情结构数据", onclick=lambda: {}),
                ui_session.put_task(self.download_market_meta_task,label='更新行情结构数据'),
                output.put_text(f"分类数量:{market_meta.category_count()}， 个股数量:{market_meta.symbol_count()}")

            ],size="200px auto")
        else:
            output.put_text(f"分类数量:{market_meta.category_count()}， 个股数量:{market_meta.symbol_count()}")

        output.put_markdown("----")

        """
         {
                    "label":(str) option label,
                    "value":(object) option value,
                    "selected":(bool, optional) whether the option is initially selected,
                    "disabled":(bool, optional) whether the option is initially disabled
                }
        """
        options = []
        options.append({
            "label": "按分类",
            "value": 3,
        })

        options.append({
            "label": "按个股",
            "value": 2,
        })

        output.put_tabs([
            {'title': '行业分类', 'content': [
                output.put_scope("category")

            ]},
            {'title': '成员个股', 'content': [output.put_scope("symbol_list")]},
            {'title': '排名数据', 'content': [output.put_scope("rank_data_scope")]},

        ])
        await self.show_category()
        await self.on_category_type_select_changed(None)
        await self.show_symbol_list()
        await self.show_rank_data()

    async def show_rank_data(self):
        rank_ui = RankDBUI(self.market)
        with output.use_scope("rank_data_scope",clear=True):
            await rank_ui.show()


    async def show_symbol_list(self):
        market = self.market
        market_meta = self.market.get_meta()
        if not isinstance(market_meta, MarketMetaStorage):
            output.put_text("MarketMeta实现类错误！")
            return
        looper = asyncio.get_running_loop()
        symbol_meta_list = await looper.run_in_executor(None, lambda: market_meta._get_all_category_symbols())
        self.symbol_manager: PageResult[CategorySymbolMeta] = CategoryPageManager(symbol_meta_list)

        async def _on_search():
            q_symbol = await pin.pin['q_symbol']
            c_symbol = await pin.pin['c_symbol']
            self.symbol_manager.search(q_symbol,c_symbol)
            await _refresh_page_select()
            await self._refresh_show_symbol_list()



        async def _refresh_page_select():
            _option_data_ = []
            _cur_page_result:PageResult[CategorySymbolMeta] = self.symbol_manager.cur_page_result()
            selected_index = _cur_page_result.cur_page()
            for page_index in range(1,_cur_page_result.total_page_count()+1):
                _option_data_.append({
                    "label": f"第{page_index}页",
                    "value": page_index,
                    "selected": selected_index == page_index
                }
                )
            pin.pin_update('symbol_pages', options=_option_data_)

        async def _on_page_changed(page_index):
            _cur_page_result: PageResult[CategorySymbolMeta] = self.symbol_manager.cur_page_result()
            _cur_page_result.turn_page(page_index)
            await self._refresh_show_symbol_list()

        with output.use_scope("symbol_list",clear=True):
            market_meta = market.get_meta()

            output.put_row([
                #output.put_text(""),
                pin.put_input("q_symbol",placeholder="个股代码、名称",),
                #output.put_text("行业代码，名称"),
                pin.put_input("c_symbol",placeholder="行业代码"),
                output.put_button("搜索", onclick=_on_search),
                pin.put_select('symbol_pages',options=[]),
            ])
            output.put_markdown("---------")
            output.put_scope("symbol_list_result")
        pin.pin_on_change("symbol_pages",onchange=_on_page_changed)
        await _refresh_page_select()
        await self._refresh_show_symbol_list()

    async def _refresh_show_symbol_list(self):

        _cur_page_result: PageResult[CategorySymbolMeta] = self.symbol_manager.cur_page_result()

        with output.use_scope("symbol_list_result",clear=True):
            data_list = []
            data_list.append(["", "code", "name", "所属行业",'weight'])
            symbol_metas = _cur_page_result.get_data()
            for index, meta in enumerate(symbol_metas):
                offset = (_cur_page_result.cur_page() -1 ) * _cur_page_result.page_size() + index + 1
                data_list.append([
                    str(offset),
                    output.put_button(meta.code,
                                      small=True,
                                      color='light',
                                      onclick=functools.partial(self._show_symbol_chart, meta)),
                    meta.name,
                    output.put_button(meta.category_code,
                                      small=True,
                                      color='light',
                                      onclick=functools.partial(self._show_category_chart, meta.category_code)),

                    str(meta.weight)
                ])
            output.put_table(data_list)

    async def show_category(self):
        market = self.market
        with output.use_scope("category", clear=True):
            type_name_map = market.get_meta().get_category_type_name_map()
            category_type_option = [
                {"label": "全部",
                 "value": None,
                 "selected": True}
            ]

            for _type, _name in type_name_map.items():
                category_type_option.append({
                    "label": f"{_name}({_type})",
                    "value": _type,
                })
            pin.put_radio("category_type", category_type_option, inline=True,label="行业分类类型")
            output.put_markdown("---")
            output.put_scope("category_symbol")
        pin.pin_on_change("category_type", onchange=self.on_category_type_select_changed)

    async def on_category_type_select_changed(self,data):
        c_type = await pin.pin['category_type']
        market = self.market
        market_meta = market.get_meta()
        looper = asyncio.get_running_loop()
        category_metas = await looper.run_in_executor(None,lambda :market_meta.get_all_category_metas(type=c_type))

        with  output.use_scope("category_symbol", clear=True):
            if not category_metas:
                output.put_text("无行业分类数据")
                return
            data_list = []
            data_list.append(["", "code", "name", "操作"])
            for index,meta in enumerate(category_metas):
                data_list.append([
                                  str(index),
                                  meta.code,
                                  meta.name,
                                output.put_row([
                                    output.put_button("成分股",
                                                      small=True,
                                                      color='light',
                                                      onclick=functools.partial(self._pop_category_member_list, meta)),
                                    output.put_button("行情图",
                                                      small=True,
                                                      color='light',
                                                      onclick=functools.partial(self._show_category_chart, meta)),
                                ])

                ])
            output.put_table(data_list)

    def _pop_category_member_list(self,meta:CategoryMeta):
        if not meta:
            output.toast("未知行业！")
            return
        market = self.market
        metas = market.get_meta().get_category_symbol_metas(meta.code)
        title = f"{meta.name}({meta.code}) 的成分股({len(metas)})"
        with output.popup(title):
            if not metas:
                output.put_text("无数据")
                return
            data_list = []
            data_list.append(["code", "name","" ,"code","name"])
            for i in range(0,len(metas),2):
                member_meta1 = metas[i]
                member_meta2 = None
                if i+1 < len(metas):
                    member_meta2 = metas[i+1]

                data_list.append([member_meta1.code,
                                  member_meta1.name,
                                   "",
                                   member_meta2.code if member_meta2 else "",
                                  member_meta2.name if member_meta2 else "",
                                  ])
            output.put_table(data_list)

    def _show_category_chart(self,meta:Union[CategoryMeta,str]):
        if isinstance(meta,str):
            meta = self.market.get_meta().get_category_meta(meta)
        if not meta:
            output.toast("未知行业！")
            return
        self._popup_chart(meta.code,meta.name,category_type=meta.type)

    def _show_symbol_chart(self, meta: CategorySymbolMeta):
        self._popup_chart(meta.code,meta.name,None)

    def _popup_chart(self, code:str,name:str,category_type:int = None):
        market = self.market


        try:
            day_db = market.get_today_db(category_type)
        except NotImplementedError:
            day_db = None

        try:
            bar_db = market.get_bar_db(category_type)
        except NotImplementedError:
            bar_db = None

        dialog.popup_chart(bar_db, day_db, code, name)



class CategoryPageManager(PageResult[CategorySymbolMeta]):

    def __init__(self,data_list:List[CategorySymbolMeta]):
        self.data_list = data_list
        self.page_list = []
        self._symbol_query = ""
        self._category_query = ""
        self._search_result = None
        page_size = self.page_size()
        cur_pages = []
        self._page_index = 1
        for i in range(0,len(self.data_list)):
            if i % page_size == 0:
                cur_pages = []
                self.page_list.append(cur_pages)
            cur_pages.append(self.data_list[i])


    def cur_page(self)->int:
        return self._page_index

    def get_data(self)->List[CategorySymbolMeta]:
        _cure_page = self.cur_page()
        if _cure_page >= len(self.page_list):
            return []
        return self.page_list[self.cur_page()-1]

    def turn_page(self,index):
        assert index > 0
        self._page_index = index

    def page_size(self):
        return 50

    def total_page_count(self)->int:
        return len(self.page_list)

    def cur_page_result(self)->PageResult[CategorySymbolMeta]:
        if self._search_result:
            return self._search_result
        return self

    def get_search_result(self)->PageResult[CategorySymbolMeta]:
        return self._search_result

    def search(self,symobl_query:str,category_query:str):
        if self._symbol_query == symobl_query and self._category_query == category_query:
            return
        self._symbol_query = symobl_query.strip()
        self._category_query = category_query.strip()
        result_data = []
        for s_meta in self.data_list:
            if  len(symobl_query) > 0 and \
                    not (s_meta.code.__contains__(symobl_query) or s_meta.name.__contains__(symobl_query)) :
                continue
            if  len(category_query) > 0 and not s_meta.category_code.__contains__(category_query):
                continue
            result_data.append(s_meta)

        self._search_result =  default_page_result(result_data,self.page_size())

if __name__ == '__main__':
    from emi.core.App import App

